/* *********************************************************************************  
 *   This file is part of GeometryPlayground.
 *
 *   GeometryPlayground is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   GeometryPlayground is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Affero General Public License for more details.
 *
 *   You should have received a copy of the GNU Affero General Public License
 *   along with GeometryPlayground.  If not, see <http://www.gnu.org/licenses/>.
 **********************************************************************************/
 
import java.awt.*;
import java.util.LinkedList;

abstract class SphericalConstruct extends GeoConstruct {
  double[] v1={0,0,0},v2={0,0,0};
  protected SphericalConstruct(){}
  public SphericalConstruct(int t, double[] vector)
    { type=t; setXYZ(vector);setNewXYZ(vector);}
  public SphericalConstruct(int t, double[] v1, double[] v2)
    { type=t; setXYZ(v1,v2); }  
  public SphericalConstruct(int t, SphericalConstruct a, SphericalConstruct b){
    double[] vec1={0,0,0}, vec2={0,0,0};
    type=t;
    constList.add(a);
    constList.add(b);
    constList.get(0).getXYZ(vec1);
    constList.get(1).getXYZ(vec2);
    this.setXYZ(vec1, vec2);    
  }
  public SphericalConstruct(int t, double[] v, SphericalConstruct a) {
    type=t;
    constList.add(a);
	this.setXYZ(v);
  }
  public SphericalConstruct(int t, LinkedList<GeoConstruct> clickedList){
	  type=t;
	  for(int i=0;i<clickedList.size();i++)
		  constList.addLast(clickedList.get(i));
	  if (constList.size()==2) {
	    double[] vec1={0,0,0}, vec2={0,0,0};
	    constList.get(0).getXYZ(vec1);
        constList.get(1).getXYZ(vec2);
        this.setXYZ(vec1, vec2);
	  }
	  else {
	  }
  }
  public SphericalConstruct(int t, LinkedList<GeoConstruct> clickedList,double[] v){
	  type=t;
	  for(int i=0;i<clickedList.size();i++)
		  constList.addLast(clickedList.get(i));
	  if (t==GeoConstruct.DISTANCE) {
	    double[] v0={0,0,0};
		constList.get(0).get(0).getXYZ(v);
		constList.get(0).get(1).getXYZ(v0);
		for (int i=0;i<2;i++) v[i]=(v[i]+v0[i])/2;
	  }
	  if (t==GeoConstruct.RATIO) {
		double[] v0={0,0,0};
		constList.get(0).getXYZ(v);
		constList.get(1).getXYZ(v0);
		for (int i=0;i<2;i++) v[i]=(v[i]+v0[i])/2;
	  }
	  setXYZ(v);
	  update();
  }
   
  public abstract SphericalPoint intersect(int m,SphericalConstruct a);
  
  public void setXYZ(double[] vector) {
	MathEqns.normalize(vector);
	x=vector[0]; y=vector[1]; z=vector[2];
	newX=x;		newY=y;		newZ=z;
    }
  public void setXYZ(double[] v1, double[] v2) {
    v2[2]+=.00000001;
    double[] normal={v1[1]*v2[2]-v2[1]*v1[2],
	                 v2[0]*v1[2]-v1[0]*v2[2],
					 v1[0]*v2[1]-v2[0]*v1[1]}; // normal vector	   
	setXYZ(normal);
    }
  public void setNewXYZ(double[] vector) {
    MathEqns.normalize(vector);
	newX=vector[0]; newY=vector[1]; newZ=vector[2];
  }
  public void setNewXYZ(double[] v1, double[] v2) {
    v2[2]+=.00000001;
	double[] normal={v1[1]*v2[2]-v2[1]*v1[2],
	                 v2[0]*v1[2]-v1[0]*v2[2],
					 v1[0]*v2[1]-v2[0]*v1[1]}; // normal vector	   
	setNewXYZ(normal);
  }

  public void translate(double[] dragStart, double[] dragNow){
    double[] norm={0,0,0};
    double w=0;

    MathEqns.crossProduct(dragStart,dragNow,norm);    
    double theta=Math.acos(MathEqns.dotProduct(dragNow,dragStart));
    w=Math.cos(theta/2);
    for (int i=0;i<3;i++) norm[i]*=Math.sin(theta/2);

    MathEqns.rotate(w,norm[0],norm[1],norm[2],this);
  }
  public void transform(GeoConstruct fixedObject,double[] dragStart,double[] dragNow) {
    MathEqns.transform(fixedObject,this,dragStart,dragNow);
  }
} // end class 


class SphericalPoint extends SphericalConstruct{
	protected int sz;
  public SphericalPoint(int t, double[] vector) {super(t,vector);}
  public SphericalPoint(int t, double[] v1, double[] v2) {super(t,v1,v2);} 
  public SphericalPoint(int t, double[] v, SphericalConstruct a) {super(t,v,a);}
  public SphericalPoint(int t, SphericalConstruct a, SphericalConstruct b){super(t,a,b);}
  public SphericalPoint(int t, LinkedList<GeoConstruct> clickedList,double[] v){super(t,clickedList,v);}
  
  public SphericalPoint intersect(int m, SphericalConstruct a){
  	SphericalPoint newPoint=new SphericalPoint(LINEintLINE0+m,a,this);
  	return newPoint;
  }
    
  public void draw(Graphics g, int SZ, boolean New) {
   sz=(int)MathEqns.max(4,SZ/40);
   if ((New && isRealNew) || (!New && isReal)) { 
    if (New) getNewXYZ(v1);
    else getXYZ(v1);
    switch (GeoPlayground.model) {
	  case 0:
	    break;
	  case 1:
	    if (v1[2]==-1) v1[2]=-.99999999;
	    v1[0]/=(1+v1[2]);
		v1[1]/=(1+v1[2]);
		break;
	  case 2:
	    if (v1[1]==1) v1[1]=.99999999;
		if (v1[1]==-1) v1[1]=-.99999999;
		double phi=Math.acos(v1[1]), theta=Math.acos(v1[0]/Math.sqrt(1-v1[1]*v1[1]));
		if (v1[2]<0) theta*=-1;
		v1[1]=Math.log(Math.tan(Math.PI/2-phi/2))/Math.PI;
		v1[0]=-theta/Math.PI;
	    break;//*/
	}
	if ((v1[2]>0 && GeoPlayground.model==0) || GeoPlayground.model!=0) {
	  if (getType()<30) {
		g.fillOval(SZ+(int)(SZ*v1[0])-sz/2,SZ+(int)(SZ*v1[1])-sz/2,sz,sz);
		if (getLabelShown())
		  g.drawString(""+(char)('A'+ID%26)+""+(ID/26),SZ+(int)(SZ*v1[0])-sz/2,SZ+(int)(SZ*v1[1])-sz/2);
	  }
	 }
   }
  }
  
  public boolean mouseIsOver(double[] v1, int SZ){
    double sz=MathEqns.max(6,SZ/20);
    return ((x-v1[0])*(x-v1[0])+(y-v1[1])*(y-v1[1])<sz*sz/(SZ*SZ));
  }
  
  public void updatePTonLINE() {
	  double[] nm={0,0,0},bn={0,0,0};
	  setValidNew(get(0).getValidNew());
	  if (getValidNew()) {
		  constList.get(0).getNewXYZ(v2);
		  MathEqns.crossProduct(v1,v2,nm);
		  MathEqns.crossProduct(v2,nm,bn);
		  MathEqns.normalize(bn);
		  setNewXYZ(bn);
	  }
  }
  public void updatePTonCIRC() {
	  double[] nm={0,0,0},bn={0,0,0};
	  setValidNew(get(0).getValidNew());
	  if (getValidNew()) {
		  constList.get(0).get(0).getNewXYZ(v2);
		  MathEqns.crossProduct(v1,v2,nm);
		  MathEqns.crossProduct(v2,nm,bn);
		  MathEqns.normalize(bn);
		  constList.get(0).get(1).getNewXYZ(nm);
		  double phi=Math.acos(MathEqns.dotProduct(v2,nm));
		  for (int i=0;i<3;i++) v1[i]=Math.cos(phi)*v2[i]+Math.sin(phi)*bn[i];
		  setNewXYZ(v1);
	  }
  }
  public void update() {
	  getNewXYZ(v1);
  }
}

class SphericalLine extends SphericalConstruct{
  double[] vec1={0,0,0}, vec2={0,0,0};
  double[] norm={0,0,0},binorm={0,0,0};
  
  public SphericalLine(int t, LinkedList<GeoConstruct> clickedList){super(t,clickedList);}
  
  public SphericalPoint intersect(int m, SphericalConstruct a){
  	SphericalPoint newPoint;
  	if(a.getType()==0)
  		newPoint=intersect(m,(SphericalCircle)a);
  	else
  		newPoint=intersect(m,(SphericalLine)a);
  	return newPoint;
  }

  public SphericalPoint intersect(int m, SphericalLine a){
  	SphericalPoint newPoint=new SphericalLINEintLINE(LINEintLINE0+m,a,this);
	if (m>0) {
	  newPoint.x*=-1;		newPoint.y*=-1;		newPoint.z*=-1;
	  newPoint.newX*=-1;	newPoint.newY*=-1;	newPoint.newZ*=-1;
	}
  	return newPoint;
  }
  
  public SphericalPoint intersect(int m, SphericalCircle a){
  	SphericalPoint newPoint=a.intersect(m,this);
  	return newPoint;
  }

  public void draw(Graphics g, int SZ, boolean New) {
   if ((New && isRealNew) || (!New && isReal)) {
	if(New){
      constList.get(0).getNewXYZ(vec1);	constList.get(1).getNewXYZ(vec2);
    }
    else{
      constList.get(0).getXYZ(vec1);	constList.get(1).getXYZ(vec2);
    }
    MathEqns.crossProduct(vec1, vec2, norm);
    MathEqns.crossProduct(vec1, norm, binorm);
	if (type==BISECTOR) {
	  if (New) {
	    getNewXYZ(vec2);	constList.get(1).getNewXYZ(vec1);
	  }
	  else {
	    getXYZ(vec2);		constList.get(1).getXYZ(vec1);
	  }
	  MathEqns.crossProduct(vec1, vec2, binorm);
	}
    double[] v1={0,0,0},v2={0,0,0};
	if (type!=SEGMENT)
    for (int i=-44*GeoPlayground.model;i<44;i++) {
      v1[0]=vec1[0]*Math.cos(i/14.)+binorm[0]*Math.sin(i/14.);
      v1[1]=vec1[1]*Math.cos(i/14.)+binorm[1]*Math.sin(i/14.);
      v1[2]=vec1[2]*Math.cos(i/14.)+binorm[2]*Math.sin(i/14.);
      v2[0]=vec1[0]*Math.cos((i+1)/14.)+binorm[0]*Math.sin((i+1)/14.);
      v2[1]=vec1[1]*Math.cos((i+1)/14.)+binorm[1]*Math.sin((i+1)/14.);
      v2[2]=vec1[2]*Math.cos((i+1)/14.)+binorm[2]*Math.sin((i+1)/14.);
      switch (GeoPlayground.model) {
		  case 0:
		    if (v1[2]*v2[2]>0) {
			  MathEqns.normalize(v1);
			  MathEqns.normalize(v2);
			  MathEqns.makeStandard(v1);
			  MathEqns.makeStandard(v2);
			  g.drawLine(SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]),
                         SZ+(int)(SZ*v2[0]),SZ+(int)(SZ*v2[1]));
			}
			else if (getLabelShown()) 
			  g.drawString(""+(char)('A'+ID%26)+""+(ID/26),SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]));
			break;
		  case 1:
		    if (v1[2]==-1) v1[2]=-.99999999;
			if (v2[2]==-1) v2[2]=-.99999999;
			v1[0]/=(1+v1[2]);	v1[1]/=(1+v1[2]);
			v2[0]/=(1+v2[2]);	v2[1]/=(1+v2[2]);
			if (v1[2]>-.9 && v2[2]>-.9)
			g.drawLine(SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]),
                       SZ+(int)(SZ*v2[0]),SZ+(int)(SZ*v2[1]));
			if (v1[2]*v2[2]<=0 && getLabelShown() && i<=0)
			  g.drawString(""+(char)('A'+ID%26)+""+(ID/26),SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]));
			break;
		  case 2:
		    if (v1[1]==1) v1[1]=.99999999;
		    if (v2[1]==1) v2[1]=.99999999;
		    if (v1[1]==-1) v1[1]=-.99999999;
			if (v2[1]==-1) v2[1]=-.99999999;
			double phi=Math.acos(v1[1]),
		       theta=Math.acos(v1[0]/Math.sqrt(1-v1[1]*v1[1]));
			if (v1[2]<0) theta*=-1;
			v1[1]=Math.log(Math.tan(Math.PI/2-phi/2))/Math.PI;
			v1[0]=-theta/Math.PI;
			phi=Math.acos(v2[1]);
			theta=Math.acos(v2[0]/Math.sqrt(1-v2[1]*v2[1]));
			if (v2[2]<0) theta*=-1;
			v2[1]=Math.log(Math.tan(Math.PI/2-phi/2))/Math.PI;
			v2[0]=-theta/Math.PI;
			if ((v1[0]-v2[0])*(v1[0]-v2[0])+(v1[1]-v2[1])*(v1[1]-v2[1])<1.5)
			  g.drawLine(SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]),
                         SZ+(int)(SZ*v2[0]),SZ+(int)(SZ*v2[1]));
			if (getLabelShown() && i==11)
			  g.drawString(""+(char)('A'+ID%26)+""+(ID/26),SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]));
			break;
	  }
	}
   }
  }  

  public boolean mouseIsOver(double[] v1, int SZ){
    double[] v2={0,0,0};
	v2[0]=x;v2[1]=y;v2[2]=z;
    return Math.abs(Math.asin(MathEqns.dotProduct(v1,v2)))< 0.02;
  }
  public void update() {
    double[] v1={0,0,0},v2={0,0,0};
	//boolean nowValid=true;
	//for (int i=0;i<getSize();i++) nowValid=(nowValid && constList.get(i).getValidNew());
	//if (nowValid) {
		setValidNew(true);
	    constList.get(0).getNewXYZ(v1);
	    constList.get(1).getNewXYZ(v2);
		if (type!=BISECTOR) {
			if (MathEqns.norm(v1,v2)<.00001) setValidNew(false);
			else setNewXYZ(v1,v2);
		}
	//}
    //else setValidNew(false);
  }
}

class SphericalCircle extends SphericalConstruct{
    double[] vec1={0,0,0}, vec2={0,0,0};
	  double[] norm={0,0,0},binorm={0,0,0};
  public SphericalCircle(int t, SphericalConstruct a, SphericalConstruct b) {super(t,a,b);}
  
  public SphericalPoint intersect(int m, SphericalConstruct a){
  	SphericalPoint newPoint;
  	if(a.getType()==0)
  		newPoint=intersect(m,(SphericalCircle)a);
  	else
  		newPoint=intersect(m,(SphericalLine)a);
  	return newPoint;
  }
  public SphericalPoint intersect(int m, SphericalLine a){
  	SphericalPoint newPoint=new SphericalCIRCintLINE(CIRCintLINE0+m,this,a);
  	newPoint.setXYZ(getCLxyz(newPoint,a,m));
  	return newPoint;
  }
  
  public SphericalPoint intersect(int m, SphericalCircle a){
  	SphericalPoint newPoint=new SphericalCIRCintCIRC(CIRCintCIRC00+m,this,a);
  	newPoint.setXYZ(getCCxyz(newPoint,a,m));
  	return newPoint;
  }
  
  public void draw(Graphics g, int SZ, boolean New) {
   if ((New && isRealNew) || (!New && isReal)) {
    double[] axis={0,0,0}, p0={0,0,0}, p1={0,0,0}, p2={0,0,0};
	if(New){
      constList.get(0).getNewXYZ(axis);
      constList.get(1).getNewXYZ(p0);
    }
    else{
      constList.get(0).getXYZ(axis);
      constList.get(1).getXYZ(p0);
    }
	double d=MathEqns.dotProduct(axis,p0);
	for (int i=0;i<3;i++) p1[i]=p0[i]-d*axis[i];
	MathEqns.crossProduct(axis,p1,p2);
	MathEqns.normalize(p2);
	d=Math.sqrt(MathEqns.dotProduct(p1,p1));
	for (int i=0;i<3;i++) p2[i]*=d;
	d=Math.sqrt(1-MathEqns.dotProduct(p2,p2));
	if (Math.acos(MathEqns.dotProduct(axis,p0))>Math.PI/2) d*=-1;
	for (int i=0;i<88;i++) {
	  double[] v1={0,0,0},v2={0,0,0};
	  for (int j=0;j<3;j++) {
	    v1[j]=p1[j]*Math.cos(i/14.)+p2[j]*Math.sin(i/14.)+d*axis[j];
		v2[j]=p1[j]*Math.cos((i+1)/14.)+p2[j]*Math.sin((i+1)/14.)+d*axis[j];
	  }
      switch (GeoPlayground.model) {
	    case 0:
		  if (v1[2]>0 && v2[2]>0) {
			g.drawLine(SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]),
					   SZ+(int)(SZ*v2[0]),SZ+(int)(SZ*v2[1]));
		  }
		  //else if (v1[2]<0 && v2[2]<0) g.drawOval(SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]),1,1);  //08_08_12
		  break;
		case 1:
		  if (v1[2]==-1) v1[2]=-.99999999;
		  if (v2[2]==-1) v2[2]=-.99999999;
		  v1[0]/=(1+v1[2]);	v1[1]/=(1+v1[2]);
		  v2[0]/=(1+v2[2]);	v2[1]/=(1+v2[2]);
		  g.drawLine(SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]),
					 SZ+(int)(SZ*v2[0]),SZ+(int)(SZ*v2[1]));
		  break;
		case 2:
		  if (v1[1]==1) v1[1]=.99999999;
		  if (v2[1]==1) v2[1]=.99999999;
		  if (v1[1]==-1) v1[1]=-.99999999;
		  if (v2[1]==-1) v2[1]=-.99999999;
		  double phi=Math.acos(v1[1]),
				 psi=Math.acos(v1[0]/Math.sqrt(1-v1[1]*v1[1]));
		  if (v1[2]<0) psi*=-1;
		  v1[1]=Math.log(Math.tan(Math.PI/2-phi/2))/Math.PI;
		  v1[0]=-psi/Math.PI;
		  phi=Math.acos(v2[1]);
		  psi=Math.acos(v2[0]/Math.sqrt(1-v2[1]*v2[1]));
		  if (v2[2]<0) psi*=-1;
		  v2[1]=Math.log(Math.tan(Math.PI/2-phi/2))/Math.PI;
		  v2[0]=-psi/Math.PI;
		  if ((v1[0]-v2[0])*(v1[0]-v2[0])+(v1[1]-v2[1])*(v1[1]-v2[1])<1.5)
			g.drawLine(SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]),
                       SZ+(int)(SZ*v2[0]),SZ+(int)(SZ*v2[1]));
		  break;
	  }
    }
	for (int j=0;j<3;j++) p2[j]=p2[j]+d*axis[j];
	if (getLabelShown()) switch(GeoPlayground.model) {
	  case 0:
	    if (p2[2]>0)
		  g.drawString(""+(char)('A'+ID%26)+""+(ID/26),SZ+(int)(SZ*p2[0]),SZ+(int)(SZ*p2[1]));
	    break;
	  case 1:
	    if (p2[2]==-1) p2[2]=-.99999999;
		p2[0]/=(1+p2[2]);	p2[1]/=(1+p2[2]);
	    if (p2[2]>0)
		  g.drawString(""+(char)('A'+ID%26)+""+(ID/26),SZ+(int)(SZ*p2[0]),SZ+(int)(SZ*p2[1]));
		else
		  g.drawString(""+(char)('A'+ID%26)+""+(ID/26),SZ-(int)(SZ*p2[0]),SZ-(int)(SZ*p2[1]));
	    break;
	  case 2:
	    if (p2[1]==1) p2[1]=.99999999;
		if (p2[1]==-1) p2[1]=-.99999999;
		double phi=Math.acos(p2[1]), theta=Math.acos(p2[0]/Math.sqrt(1-p2[1]*p2[1]));
		if (p2[2]<0) theta*=-1;
		p2[1]=Math.log(Math.tan(Math.PI/2-phi/2))/Math.PI;
		p2[0]=-theta/Math.PI;
		g.drawString(""+(char)('A'+ID%26)+""+(ID/26),SZ+(int)(SZ*p2[0]),SZ+(int)(SZ*p2[1]));
	    break;
	
	}
   }
  }
  public boolean mouseIsOver(double[] mouse, int SZ){
    double[] axis={0,0,0}, point={0,0,0};
	constList.get(0).getXYZ(axis);
	constList.get(1).getXYZ(point);
	double theta=Math.acos(MathEqns.dotProduct(axis,point));
	for (int i=0;i<3;i++) point[i]=-axis[i];
	if (Math.asin(axis[2])<theta)
	  if (Math.abs(Math.acos(MathEqns.dotProduct(axis,mouse))-theta)< 0.02 ||
	      Math.abs(Math.acos(MathEqns.dotProduct(point,mouse))-theta)< 0.02) return true;
	  else return false;
    else return Math.abs(Math.acos(MathEqns.dotProduct(axis,mouse))-theta)< 0.02;
  }
  
   public void update() {
     setValidNew(constList.get(0).getValidNew() && constList.get(1).getValidNew());
  }
  
  public double[] getCLxyz(SphericalPoint inter, SphericalConstruct b, int i) {
    double[] u={0,0,0},v={0,0,0},w={0,0,0},x={0,0,0};
	constList.get(0).getXYZ(u);					// a is a circle
	constList.get(1).getXYZ(v);					// b is a line
	b.getXYZ(w);					// we find a pt of intersection.
	if (i==0) inter.setValid(CircleEqns.calculateCL(u,v,w,x,true));
	else inter.setValid(CircleEqns.calculateCL(u,v,w,x,false));
	return x;
  }
  
  public double[] getNewCLxyz(SphericalPoint inter,SphericalConstruct b, int i) {
    double[] u={0,0,0},v={0,0,0},w={0,0,0},x={0,0,0};
	constList.get(0).getNewXYZ(u);					// a is a circle
	constList.get(1).getNewXYZ(v);					// b is a line
	b.getNewXYZ(w);					// we find a pt of intersection.
	if (i==0) inter.isRealNew=CircleEqns.calculateCL(u,v,w,x,true);
	else inter.isRealNew=CircleEqns.calculateCL(u,v,w,x,false);
	return x;
  }
  
  public double[] getCCxyz(SphericalPoint inter,SphericalConstruct b, int i) {
    double[] t={0,0,0},u={0,0,0},v={0,0,0},w={0,0,0},x={0,0,0};
	constList.get(0).getXYZ(t);					// a is a circle
	constList.get(1).getXYZ(u);					// b is a circle
	b.get(0).getXYZ(v);				// we find a pt of intersection.
	b.get(1).getXYZ(w);
	switch (i) {
	  case 0: inter.setValid(CircleEqns.calculateCC0(t,u,v,w,x,true));  break;
	  case 1: inter.setValid(CircleEqns.calculateCC0(t,u,v,w,x,false)); break;
	}
	return x;
  }
  public double[] getNewCCxyz(SphericalPoint inter,SphericalConstruct b, int i) {
    double[] t={0,0,0},u={0,0,0},v={0,0,0},w={0,0,0},x={0,0,0};
	constList.get(0).getNewXYZ(t);					// a is a circle
	constList.get(1).getNewXYZ(u);					// b is a circle
	b.get(0).getNewXYZ(v);			// we find a pt of intersection.
	b.get(1).getNewXYZ(w);
	switch (i) {
	  case 0: inter.isRealNew=CircleEqns.calculateCC0(t,u,v,w,x,true);  break;
	  case 1: inter.isRealNew=CircleEqns.calculateCC0(t,u,v,w,x,false); break;
	}
	return x;
  }  
}

class SphericalPTonLINE extends SphericalPoint {
	public SphericalPTonLINE(int t, double[] vector) {super(t, vector);}
	public SphericalPTonLINE(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public SphericalPTonLINE(int t, double[] v, SphericalConstruct a) {super(t, v, a);}
	public SphericalPTonLINE(int t, SphericalConstruct a,SphericalConstruct b) {super(t, a, b);}
	public SphericalPTonLINE(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
	}
	public void update() {
		super.update();
		updatePTonLINE();
	}
}

class SphericalPTonCIRC extends SphericalPoint {
	public SphericalPTonCIRC(int t, double[] vector) {super(t, vector);}
	public SphericalPTonCIRC(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public SphericalPTonCIRC(int t, double[] v, SphericalConstruct a) {super(t, v, a);}
	public SphericalPTonCIRC(int t, SphericalConstruct a,SphericalConstruct b) {super(t, a, b);}
	public SphericalPTonCIRC(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
	}
	public void update() {
		super.update();
		updatePTonCIRC();
	}
}

class SphericalLINEintLINE extends SphericalPoint {
	public SphericalLINEintLINE(int t, double[] vector) {super(t, vector);}
	public SphericalLINEintLINE(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public SphericalLINEintLINE(int t, double[] v, SphericalConstruct a) {super(t, v, a);}
	public SphericalLINEintLINE(int t, SphericalConstruct a,SphericalConstruct b) {super(t, a, b);}
	public SphericalLINEintLINE(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
	}
	public void update() {
		double[] nm={0,0,0};
		constList.get(0).getNewXYZ(v1);
		constList.get(1).getNewXYZ(v2);
		MathEqns.crossProduct(v1,v2,nm);
		MathEqns.normalize(nm);
		if (type==LINEintLINE1) for (int i=0;i<3;i++) nm[i]*=-1;
		setValidNew(true);
		setNewXYZ(nm);
		for (int i=0;i<2;i++) if (constList.get(i).getType()==SEGMENT) {
			constList.get(i).get(0).getNewXYZ(v1);
			constList.get(i).get(1).getNewXYZ(v2);
			if (Math.abs(Math.acos(MathEqns.dotProduct(v1,v2))-Math.acos(MathEqns.dotProduct(v1,nm))-Math.acos(MathEqns.dotProduct(nm,v2)))>.0001)
				setValidNew(false);
		}
	}
}


class SphericalCIRCintLINE extends SphericalPoint {
	public SphericalCIRCintLINE(int t, double[] vector) {super(t, vector);}
	public SphericalCIRCintLINE(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public SphericalCIRCintLINE(int t, double[] v, SphericalConstruct a) {super(t, v, a);}
	public SphericalCIRCintLINE(int t, SphericalConstruct a,SphericalConstruct b) {super(t, a, b);}
	public SphericalCIRCintLINE(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
	}
	public void update() {
		setNewXYZ(((SphericalCircle)constList.get(0)).getNewCLxyz(this,(SphericalConstruct)constList.get(1),type-CIRCintLINE0));
		double[] nm={newX,newY,newZ};
		for (int i=0;i<2;i++) if (constList.get(i).getType()==SEGMENT) {
			constList.get(i).get(0).getNewXYZ(v1);
			constList.get(i).get(1).getNewXYZ(v2);
			if (Math.abs(Math.acos(MathEqns.dotProduct(v1,v2))-Math.acos(MathEqns.dotProduct(v1,nm))-Math.acos(MathEqns.dotProduct(nm,v2)))>.0001)
				setValidNew(false);
		}
	}
}

class SphericalCIRCintCIRC extends SphericalPoint {
	public SphericalCIRCintCIRC(int t, double[] vector) {super(t, vector);}
	public SphericalCIRCintCIRC(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public SphericalCIRCintCIRC(int t, double[] v, SphericalConstruct a) {super(t, v, a);}
	public SphericalCIRCintCIRC(int t, SphericalConstruct a,SphericalConstruct b) {super(t, a, b);}
	public SphericalCIRCintCIRC(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
	}
	public void update() {
		setNewXYZ(((SphericalCircle)constList.get(0)).getNewCCxyz(this,(SphericalConstruct)constList.get(1),type-CIRCintCIRC00));
	}
}

class SphericalMIDPT extends SphericalPoint {
	public SphericalMIDPT(int t, double[] vector) {super(t, vector);}
	public SphericalMIDPT(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public SphericalMIDPT(int t, double[] v, SphericalConstruct a) {super(t, v, a);}
	public SphericalMIDPT(int t, SphericalConstruct a,SphericalConstruct b) {super(t, a, b);}
	public SphericalMIDPT(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
	}
	public void update() {
		constList.get(0).getNewXYZ(v1);
		constList.get(1).getNewXYZ(v2);
		for (int i=0;i<3;i++) v1[i]+=v2[i];
		MathEqns.normalize(v1);
		setNewXYZ(v1);
		  
	}
}

class SphericalFIXedPT extends SphericalPoint {
	public SphericalFIXedPT(int t, double[] vector) {super(t, vector);}
	public SphericalFIXedPT(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public SphericalFIXedPT(int t, double[] v, SphericalConstruct a) {super(t, v, a);}
	public SphericalFIXedPT(int t, SphericalConstruct a,SphericalConstruct b) {super(t, a, b);}
	public SphericalFIXedPT(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
	}
	public void update() {
		super.update();
	}
}
class SphericalMeasure extends SphericalPoint {
    protected double[] a={0,0,0},b={0,0,0};
	public SphericalMeasure(int t, double[] vector) {super(t, vector);}
	public SphericalMeasure(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public SphericalMeasure(int t, double[] v, SphericalConstruct a) {super(t, v, a);}
	public SphericalMeasure(int t, SphericalConstruct a,SphericalConstruct b) {super(t, a, b);}
	public SphericalMeasure(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
		if (New && (getType()!=ANGLE && getType()!=RATIO)) {
			get(0).get(0).getNewXYZ(a);
			get(0).get(1).getNewXYZ(b);
		}
		else if (getType()!=ANGLE && getType()!=RATIO) {
			get(0).get(0).getXYZ(a);
			get(0).get(1).getXYZ(b);
		}
		if (v1[2]>0 || GeoPlayground.model>0) {
			g.fillRect(SZ+(int)(SZ*v1[0])-sz/2+1,SZ+(int)(SZ*v1[1])-sz/2+1,sz-2,sz-2);
			g.drawLine(SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]),SZ+(int)(SZ*v1[0])+10,SZ+(int)(SZ*v1[1])-5);
		}		
	}

}
class SphericalRATIO extends SphericalMeasure {
	public SphericalRATIO(int t, double[] vector) {super(t, vector);}
	public SphericalRATIO(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public SphericalRATIO(int t, double[] v, SphericalConstruct a) {super(t, v, a);}
	public SphericalRATIO(int t, SphericalConstruct a,SphericalConstruct b) {super(t, a, b);}
	public SphericalRATIO(int t, LinkedList<GeoConstruct> clickedList,double[] v) {
		super(t, clickedList, v);
	}
	public void draw(Graphics g, int SZ, boolean New) {
		if ((New && getValidNew()) || (!New && getValid())) {
		super.draw(g, SZ, New);
		String[] ratioText={"",""};
		double[] ratioVar={0,0};
		for (int i=0;i<2;i++) {
			if (New) {
				get(i).get(0).get(0).getNewXYZ(a);
				get(i).get(0).get(1).getNewXYZ(b);
			}
			else {
				get(i).get(0).get(0).getXYZ(a);
				get(i).get(0).get(1).getXYZ(b);
			}
			switch(get(i).getType()) {
			case DISTANCE:
				ratioText[i]="d("+(char)('A'+get(i).get(0).get(0).getID()%26)+""+(get(i).get(0).get(0).getID()/26)+","
				+(char)('A'+get(i).get(0).get(1).getID()%26)+""+(get(i).get(0).get(1).getID()/26)+")";
				ratioVar[i]=Math.acos(MathEqns.dotProduct(a,b));
				break;
			case ANGLE:
				double[] c={0,0,0};
				if (New) get(i).get(0).get(2).getNewXYZ(c);
				else get(i).get(0).get(2).getXYZ(c);
				ratioText[i]="m\u2220("+(char)('A'+get(i).get(0).get(0).getID()%26)+""+(get(i).get(0).get(0).getID()/26)+","
				+(char)('A'+get(i).get(0).get(1).getID()%26)+""+(get(i).get(0).get(1).getID()/26)+","
				+(char)('A'+get(i).get(0).get(2).getID()%26)+""+(get(i).get(0).get(2).getID()/26)+")";
				ratioVar[i]=MathEqns.sphAngle(a,b,c);
				break;
			case AREA:
				ratioText[i]="a("+(char)('A'+get(i).get(0).getID()%26)+""+(get(i).get(0).getID()/26)+")";
				ratioVar[i]=(2-2*MathEqns.dotProduct(a,b))*Math.PI;
				break;
			case CIRCUMF:
				ratioText[i]="c("+(char)('A'+get(i).get(0).getID()%26)+""+(get(i).get(0).getID()/26)+")";
				ratioVar[i]=(2*Math.sqrt(1-MathEqns.dotProduct(a,b)*MathEqns.dotProduct(a,b)))*Math.PI;
				break;
			}
		}
		String calcText="-";
		if (ratioVar[1]!=0) calcText=""+MathEqns.chop(ratioVar[0]/ratioVar[1]);
		g.drawString(ratioText[0]+":"+ratioText[1]+"\u2248"+calcText,SZ+(int)(SZ*v1[0])+13,SZ+(int)(SZ*v1[1]));
		}
	}
	public void update() {
		super.update();
	}
}


class SphericalDISTANCE extends SphericalMeasure {
	public SphericalDISTANCE(int t, double[] vector) {super(t, vector);}
	public SphericalDISTANCE(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public SphericalDISTANCE(int t, double[] v, SphericalConstruct a) {super(t, v, a);}
	public SphericalDISTANCE(int t, SphericalConstruct a,SphericalConstruct b) {super(t, a, b);}
	public SphericalDISTANCE(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
		if (v1[2]>0 || GeoPlayground.model>0)
		g.drawString("d("+(char)('A'+get(0).get(0).getID()%26)+""+(get(0).get(0).getID()/26)+","
				   +(char)('A'+get(0).get(1).getID()%26)+""+(get(0).get(1).getID()/26)+")\u2248"
				   +MathEqns.chop(Math.acos(MathEqns.dotProduct(a,b))/Math.PI)+"\u03c0",
				   SZ+(int)(SZ*v1[0])+13,SZ+(int)(SZ*v1[1]));
	}
	public void update() {
		super.update();
		updatePTonLINE();
	}
}

class SphericalANGLE extends SphericalMeasure {
	public SphericalANGLE(int t, double[] vector) {super(t, vector);}
	public SphericalANGLE(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public SphericalANGLE(int t, double[] v, SphericalConstruct a) {super(t, v, a);}
	public SphericalANGLE(int t, SphericalConstruct a,SphericalConstruct b) {super(t, a, b);}
	public SphericalANGLE(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
		double[] c={0,0,0};
		if (New) {
		    get(0).get(0).getNewXYZ(a);
		    get(0).get(1).getNewXYZ(b);
		    get(0).get(2).getNewXYZ(c);
		}
		else {
			get(0).get(0).getXYZ(a);
			get(0).get(1).getXYZ(b);
			get(0).get(2).getXYZ(c);
		}
		if (v1[2]>0 || GeoPlayground.model>0)
		g.drawString("m\u2220("+(char)('A'+get(0).get(0).getID()%26)+""+(get(0).get(0).getID()/26)+","
						       +(char)('A'+get(0).get(1).getID()%26)+""+(get(0).get(1).getID()/26)+","
						       +(char)('A'+get(0).get(2).getID()%26)+""+(get(0).get(2).getID()/26)+")\u2248"
						       +MathEqns.chop(MathEqns.sphAngle(a,b,c))+"\u00b0",
						       SZ+(int)(SZ*v1[0])+13,SZ+(int)(SZ*v1[1]));
	}
	public void update() {
		super.update();
		updatePTonLINE();
	}
}

class SphericalCIRCUMF extends SphericalMeasure {
	public SphericalCIRCUMF(int t, double[] vector) {super(t, vector);}
	public SphericalCIRCUMF(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public SphericalCIRCUMF(int t, double[] v, SphericalConstruct a) {super(t, v, a);}
	public SphericalCIRCUMF(int t, SphericalConstruct a,SphericalConstruct b) {super(t, a, b);}
	public SphericalCIRCUMF(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
		if (v1[2]>0 || GeoPlayground.model>0)
		g.drawString("c("+(char)('A'+get(0).getID()%26)+""+(get(0).getID()/26)+")\u2248"
				+MathEqns.chop(2*Math.sqrt(1-MathEqns.dotProduct(a,b)*MathEqns.dotProduct(a,b)))+"\u03c0",
				SZ+(int)(SZ*v1[0])+13,SZ+(int)(SZ*v1[1]));
	}
	public void update() {
		super.update();
		updatePTonCIRC();
	}
}

class SphericalAREA extends SphericalMeasure {
	public SphericalAREA(int t, double[] vector) {super(t, vector);}
	public SphericalAREA(int t, double[] v1, double[] v2) {super(t, v1, v2);}
	public SphericalAREA(int t, double[] v, SphericalConstruct a) {super(t, v, a);}
	public SphericalAREA(int t, SphericalConstruct a,SphericalConstruct b) {super(t, a, b);}
	public SphericalAREA(int t, LinkedList<GeoConstruct> clickedList,double[] v) {super(t, clickedList, v);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
		if (v1[2]>0 || GeoPlayground.model>0)
		g.drawString("a("+(char)('A'+get(0).getID()%26)+""+(get(0).getID()/26)+")\u2248"
				+MathEqns.chop(2-2*/*Math.abs(*/MathEqns.dotProduct(a,b)/*)*/)+"\u03c0",
				SZ+(int)(SZ*v1[0])+13,SZ+(int)(SZ*v1[1]));
	}
	public void update() {
		super.update();
		updatePTonCIRC();
	}
}

class SphericalPERP extends SphericalLine {
	public SphericalPERP(int t, LinkedList<GeoConstruct> clickedList) {super(t, clickedList);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
	}
	public void update() {
		super.update();
	}
}

class SphericalSEGMENT extends SphericalLine {
	public SphericalSEGMENT(int t, LinkedList<GeoConstruct> clickedList) {super(t, clickedList);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
		double theta=Math.acos(MathEqns.dotProduct(vec1,vec2));
		  for (int i=0; i<theta*128;i++) {
			v1[0]=vec1[0]*Math.cos(i/128.)-binorm[0]*Math.sin(i/128.);
			v1[1]=vec1[1]*Math.cos(i/128.)-binorm[1]*Math.sin(i/128.);
			v1[2]=vec1[2]*Math.cos(i/128.)-binorm[2]*Math.sin(i/128.);
			v2[0]=vec1[0]*Math.cos((i+1)/128.)-binorm[0]*Math.sin((i+1)/128.);
			v2[1]=vec1[1]*Math.cos((i+1)/128.)-binorm[1]*Math.sin((i+1)/128.);
			v2[2]=vec1[2]*Math.cos((i+1)/128.)-binorm[2]*Math.sin((i+1)/128.);
			switch (GeoPlayground.model) {
			  case 0:
			    if (v1[2]>0 && v2[2]>0) {
			    g.drawLine(SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]),
	                       SZ+(int)(SZ*v2[0]),SZ+(int)(SZ*v2[1]));
				if (i>theta*133 && getLabelShown())
			      g.drawString(""+(char)('A'+ID%26)+""+(ID/26),SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]));
				}
				break;
			  case 1:
			    if (v1[2]==-1) v1[2]=-.99999999;
				if (v2[2]==-1) v2[2]=-.99999999;
				v1[0]/=(1+v1[2]);	v1[1]/=(1+v1[2]);
				v2[0]/=(1+v2[2]);	v2[1]/=(1+v2[2]);
				g.drawLine(SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]),
	                       SZ+(int)(SZ*v2[0]),SZ+(int)(SZ*v2[1]));
				if (i>theta*133 && i<=theta*133+1 && v1[2]>0 && getLabelShown())
			      g.drawString(""+(char)('A'+ID%26)+""+(ID/26),SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]));
				break;
			  case 2:
			    if (v1[1]==1) v1[1]=.99999999;
			    if (v2[1]==1) v2[1]=.99999999;
			    if (v1[1]==-1) v1[1]=-.99999999;
				if (v2[1]==-1) v2[1]=-.99999999;
				double phi=Math.acos(v1[1]),
			           psi=Math.acos(v1[0]/Math.sqrt(1-v1[1]*v1[1]));
				if (v1[2]<0) psi*=-1;
				v1[1]=Math.log(Math.tan(Math.PI/2-phi/2))/Math.PI;
				v1[0]=-psi/Math.PI;
				phi=Math.acos(v2[1]);
				psi=Math.acos(v2[0]/Math.sqrt(1-v2[1]*v2[1]));
				if (v2[2]<0) psi*=-1;
				v2[1]=Math.log(Math.tan(Math.PI/2-phi/2))/Math.PI;
				v2[0]=-psi/Math.PI;
				if ((v1[0]-v2[0])*(v1[0]-v2[0])+(v1[1]-v2[1])*(v1[1]-v2[1])<1.5)
				  g.drawLine(SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]),
	                         SZ+(int)(SZ*v2[0]),SZ+(int)(SZ*v2[1]));
				if (i>theta*67 && i<=theta*67+1 && v1[2]>0 && getLabelShown())
			      g.drawString(""+(char)('A'+ID%26)+""+(ID/26),SZ+(int)(SZ*v1[0]),SZ+(int)(SZ*v1[1]));
				break;
		      }
		  }
	}
	public void update() {
		super.update();
		
	}
}

class SphericalBISECTOR extends SphericalLine {

	public SphericalBISECTOR(int t, LinkedList<GeoConstruct> clickedList) {super(t, clickedList);}
	public void draw(Graphics g, int SZ, boolean New) {
		super.draw(g, SZ, New);
	}
	public void update() {
		double[] aa={0,0,0},bb={0,0,0},cc={0,0,0},mp={0,0,0};
		constList.get(0).getNewXYZ(aa);
		SphericalPoint a=new SphericalPoint(POINT,aa);
		constList.get(1).getNewXYZ(bb);
		SphericalPoint b=new SphericalPoint(POINT,bb);
		constList.get(2).getNewXYZ(cc);
		SphericalPoint c=new SphericalPoint(POINT,cc);
		LinkedList<GeoConstruct>tempList=new LinkedList<GeoConstruct>();
		tempList.add(a);	tempList.add(c);
		SphericalPoint m=new SphericalMIDPT(MIDPT,tempList,mp);
		m.update();	m.getNewXYZ(mp);	m.setXYZ(mp);
		if (Math.abs(MathEqns.determinant(aa,bb,cc))<.000001) {
			if (MathEqns.sphAngle(aa,bb,cc)>175) {
				SphericalCircle d=new SphericalCircle(CIRCLE,a,c);
				SphericalCircle e=new SphericalCircle(CIRCLE,c,a);
				SphericalPoint f1,f2;
				f1=((SphericalCircle)d).intersect(0,(SphericalCircle)e);
				f1.update();	f1.getNewXYZ(v1);	f1.setXYZ(v1);
				f2=((SphericalCircle)d).intersect(1,(SphericalCircle)e);
				f2.update();	f2.getNewXYZ(v2);	f2.setXYZ(v2);
				tempList.clear();	tempList.add(f1);	tempList.add(f2);
			}
			else {
				tempList.clear();	tempList.add(a);	tempList.add(b);
			}
		}
		else {
			tempList.clear();	tempList.add(b);	tempList.add(c);
			SphericalLine d=new SphericalLine(LINE,tempList);
			d.update();	d.getNewXYZ(v1);
			SphericalCircle e=new SphericalCircle(CIRCLE,b,a);
			SphericalPoint f1,f2;
			f1=((SphericalLine)d).intersect(0,(SphericalCircle)e);
			f1.update();	f1.getNewXYZ(v1);	f1.setXYZ(v1);
			f2=((SphericalLine)d).intersect(1,(SphericalCircle)e);
			f2.update();	f2.getNewXYZ(v2);	f2.setXYZ(v2);
			tempList.clear();	tempList.add(a);	tempList.add(f1);
			SphericalPoint g1=new SphericalMIDPT(MIDPT,tempList,v1);
		  	g1.update();	g1.getNewXYZ(v1);	g1.setXYZ(v1);
		  	tempList.clear();	tempList.add(a);	tempList.add(f2);
		  	SphericalPoint g2=new SphericalMIDPT(MIDPT,tempList,v2);
		  	g2.update();	g2.getNewXYZ(v2);	g2.setXYZ(v2);
		  	tempList.clear();	tempList.add(a);	tempList.add(c);
		  	SphericalPoint g3=new SphericalMIDPT(MIDPT,tempList,bb);
		  	g3.update();	g3.getNewXYZ(bb);	g3.setXYZ(bb);
		  	if (Math.acos(MathEqns.dotProduct(v1,bb))>Math.acos(MathEqns.dotProduct(v2,bb)))
				g1=g2;
		  	tempList.clear();	tempList.add(b);	tempList.add(g1);
		}
		SphericalLine h=new SphericalLine(LINE,tempList);
		h.update();	h.getNewXYZ(v1);
		if (MathEqns.norm(aa,bb)*MathEqns.norm(cc,bb)>.000000001) setNewXYZ(v1);
		else setValidNew(false);
	}
}
